package com.yboot.ssooauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;

/**
 * @Description 认证服务器 Authorization Server
 *
 * @author liuxt
 * @version 1.0.0
 * @createTime 2021-11-26 14:00:00
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;

    @Autowired
    @Qualifier("userDetailsService")
    private UserDetailsService userDetailsService;

    @Autowired
    @Qualifier("passwordEncoder")
    private PasswordEncoder passwordEncoder;
    /**
     * jwt 对称加密密钥
     */
    @Value("${spring.security.oauth2.jwt.signingKey}")
    private String signingKey;

    /**
     * token的持久化
     * 数据库存储token信息
     * 主要表：oauth_access_token、oauth_refresh_token
     * @return JwtTokenStore
     */
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(signingKey);
        return converter;
    }

    /**
     * 授权码模式持久化授权码code
     *
     * @return JdbcAuthorizationCodeServices
     */
    @Bean
    protected AuthorizationCodeServices authorizationCodeServices() {
        // 授权码存储等处理方式类，使用jdbc，操作oauth_code表
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    /**
     * 配置客户端信息存储方式
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /**
         * 配置客户端信息，从数据库中读取，对应oauth_client_details表
         *
         *
         */
        clients.jdbc(dataSource);


        /**
         * 测试用，将客户端信息存储在内存中
         * 1.生成的密值 对应数据库表oauth_client_details字段client_secret值
         * 2.client1 对应数据库表oauth_client_details字段client_id值
         *
         */
//        String client1_secret = passwordEncoder.encode("client1_secret");
//        System.out.println("client1_secret = " + client1_secret);
//        clients.inMemory()
//                // client_id
//             .withClient("client1")
//                // client_secret
//             .secret(client1_secret)
//                // 该client允许的授权类型
//             .authorizedGrantTypes("password", "authorization_code", "refresh_token")
//                // 允许的授权范围
//             .scopes("read")
//             .accessTokenValiditySeconds(3600)
//             .refreshTokenValiditySeconds(86400)
//             //加上验证回调地址
//             .redirectUris("http://www.baidu.com")
//             .autoApprove(true); //登录后绕过批准询问(/oauth/confirm_access)
    }

    /**
     * 认证相关的配置
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
                //配置授权管理认证对象
        endpoints.authenticationManager(authenticationManager)
                //配置加载用户信息的服务
                .userDetailsService(userDetailsService)
                //授权码服务,添加就可以保存到数据库了
                .authorizationCodeServices(authorizationCodeServices())
                //jwt保存的信息
                .accessTokenConverter(accessTokenConverter())
                //令牌管理服务，调用上面的方法
                .tokenStore(tokenStore())
                //支持OAUTH相关接口以GET和POST方法请求
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }

    /**
     * SecurityConfig服务器配置
     *
     * @param oauthServer
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer)  {
        //支持请求数据通过表单的形式发送(将client参数放在header或body中)
        oauthServer.allowFormAuthenticationForClients()
                //oauth/token_key是公开
                .tokenKeyAccess("isAuthenticated()")
                //oauth/check_token公开
                .checkTokenAccess("permitAll()");

    }
}
